package array

import (
	"bytes"
	"fmt"
	"go-guide/utils/intefaces"
)

// 对于数组来说，是内存里面一段连续的空间
type Array struct {
	data []interface{}
	size int
}

func Constructor(capacity int) *Array {
	return &Array{
		data: make([]interface{}, capacity),
	}
}

func (a *Array) Capacity() int {
	return len(a.data)
}

func (a *Array) Size() int {
	return a.size
}

func (a *Array) Empty() bool {
	return a.size == 0
}

// 向指定位置插入一个元素
func (a *Array) Add(index int, e interface{}) {
	a.rangeCheckIndex(index)

	if a.size == len(a.data) {
		a.resize(2 * a.size)
	}

	for i := a.size - 1; i >= index; i-- {
		a.data[i+1] = a.data[i]
	}
	a.data[index] = e
	a.size++
}

func (a *Array) AddLast(e interface{}) {
	a.Add(a.size, e)
}

func (a *Array) AddFirst(e interface{}) {
	a.Add(0, e)
}

func (a *Array) Get(index int) interface{} {
	return a.data[index]
}

// 查找对象所在的索引位置，如果不存在返回-1
func (a *Array) Find(e interface{}) int {
	for i := 0; i < a.size; i++ {
		if intefaces.Compare(a.data[i], e) == 0 {
			return i
		}
	}
	return -1
}

// 移除指定位置的元素
func (a *Array) Remove(index int) interface{} {
	a.rangeCheckIndex(index)
	e := a.data[index]
	for i := index + 1; i < a.size; i++ {
		a.data[i-1] = a.data[i]
	}
	a.size--
	a.data[a.size] = nil
	// 考虑边界情况，避免长度为0的时候，resize 为0
	if a.size == len(a.data)/4 && len(a.data)/2 != 0 {
		a.resize(len(a.data) / 2)
	}
	return e
}

func (a *Array) Contains(e interface{}) bool {
	for i := 0; i < a.size; i++ {
		if intefaces.Compare(e, a.data[i]) == 0 {
			return true
		}
	}
	return false
}

func (a *Array) rangeCheckIndex(index int) {
	if index < 0 || index > a.size {
		panic("index is illegal")
	}
}

func (a *Array) resize(newCapacity int) {
	newData := make([]interface{}, newCapacity)
	for i := 0; i < a.size; i++ {
		newData[i] = a.data[i]
	}
	a.data = newData
}

// 重写 Array 的 string 方法
func (a *Array) String() string {
	var buffer bytes.Buffer

	buffer.WriteString(fmt.Sprintf("Array: size = %d, capacity = %d\n", a.size, len(a.data)))
	buffer.WriteString("[")
	for i := 0; i < a.size; i++ {
		// fmt.Sprint 将 interface{} 类型转换为字符串
		buffer.WriteString(fmt.Sprint(a.data[i]))
		if i != (a.size - 1) {
			buffer.WriteString(", ")
		}
	}
	buffer.WriteString("]")

	return buffer.String()
}
